//linux/include/blk.h

#ifndef _BLK_H_
#define _BLK_H_

//预定义块设备数量：
#define NR_BLK_DEV	7

//预定义请求项数目：
#define NR_REQUEST	32

//对设备操作的请求项结构：
struct request {
	int dev;			//使用的设备号(-1,表示该项空闲)
	int cmd;			//操作命令(READ 或 WRITE)
	int errors;			//操作时产生的错误次数
	unsigned long sector;		//起始扇区(1块=2扇区)
	unsigned long nr_sectors;	//读/写扇区数
	char * buffer;			//对应的数据缓冲区
	struct task_struct * waiting;	//等待操作完成的任务
	struct buffer_head * bh;	//缓冲区头指针
	struct request * next;
};

//块设备结构：
struct blk_dev_struct {
	void (*request_fn)(void);	//对请求项进行操作的函数
	struct request * current_request;//当前请项指针
};

//块设备表，每种设备占用一项：
extern struct blk_dev_struct blk_dev[NR_BLK_DEV];

//请求项队列：
extern struct request request[NR_REQUEST];

//等待空闲请求项的任务：
extern struct task_struct * wait_for_request;

//下面定义的是电梯算法：
//	1.读操作总是在写操作之前进行。
//	2.同一种类型的操作，设备号小的先做。
//	3.同一种类型、同一设备号的操作，起始扇区序号小的先做。
//返回值：
//	若s1 适合放在s2前，就返回true,否则false.
#define IN_ORDER(s1, s2) 			\
	( ((s1)->cmd < (s2)->cmd)    ||    	\
	  ((s1)->cmd == (s2)->cmd && 		\
	  ( (s1)->dev < (s2)->dev || 		\
	    ( (s1)->dev == (s2)->dev && (s1)->sector < (s2)->sector )\
	  ))\
	)

	   
	  

#ifdef MAJOR_NR
// RAMDISK的主设备号是1
#if (MAJOR_NR == 1)
#define DEVICE_NAME "ramdisk"
#define DEVICE_REQUEST do_rd_request
#define DEVICE_NR(device) ((device)&7)   //次设备号0~7
#define DEVICE_ON(device)
#define DEVICE_OFF(device)

// 软驱的主设备号是2
#elif (MAJOR_NR == 2)
#define DEVICE_NAME "floppy"
#define DEVICE_INTR do_floppy
#define DEVICE_REQUEST do_fd_request
#define DEVICE_NR(device) ((device)&3)   //次设备号0~3
#define DEVICE_ON(device) floppy_on(DEVICE_NR(device))
#define DEVICE_OFF(device)

// 硬盘的主设备号是3
#elif (MAJOR_NR == 3)
#define DEVICE_NAME "harddisk"
#define DEVICE_INTR  do_hd
#define DEVICE_REQUEST do_hd_request
#define DEVICE_NR(device) (MINOR(device)/5) //次设备号0~1,每个硬盘可以有4分区
#define DEVICE_ON(device)
#define DEVICE_OFF(device)

#elif
#error "unknow blk device"
#endif

// 当前设备的当前请求项：
#define CURRENT (blk_dev[MAJOR_NR].current_request)

// 当前次设备号：
#define CURRENT_DEV DEVICE_NR(CURRENT->dev)

//设备的操作链表：
//blk_dev[MAJOR_NR]-->request[X]-->reuqest[X]-->request[X]-->NULL
//		       (CURRENT)




// 定义DEVICE_INTR为函数指针:
#ifdef DEVICE_INTR
void (*DEVICE_INTR)(void) = NULL;
#endif

//声明DEVICE_REQUEST()函数:
static void (DEVICE_REQUEST)(void);

// 对缓冲区解锁：
static inline void unlock_buffer(struct buffer_head *bh)
{
	if(!bh->b_lock) //若b_lock==0,表明缓冲区是开放的,给出提示信息
		printk(DEVICE_NAME":free buffer being unlockd\n");
	bh->b_lock = 0; //对缓冲区解锁
	wake_up(&bh->b_wait); //唤醒等待这个缓冲区的任务
}

// 设备操作请求结束：
// 	1.uptodate==1,表明设备操作成功
// 	2.uptodate==0,表明设备操作失败，给出提示信息
// 	
static inline void end_request(int uptodate)
{
	DEVICE_OFF(CURRENT->dev);//关闭当前设备
	if(CURRENT->bh){//若当前请项的缓冲区指针非空
		CURRENT->bh->b_uptodate = uptodate;//对缓冲区置更新标志 
		unlock_buffer(CURRENT->bh);//对缓冲区解锁
	}
	if(!uptodate){//若更新标志为0,表明操作不成功，显示出错信息
		printk(DEVICE_NAME" I/O error\n\r");
		printk("dev %04x, block %d\n\r", CURRENT->dev,
				CURRENT->bh->b_blocknr);
	}
	wake_up(&CURRENT->waiting);//唤醒等待该请求项的任务
	wake_up(&wait_for_request);//唤醒等待空闲请求项的任务
	CURRENT->dev = -1;	   //置当前请项为空闲
	CURRENT = CURRENT->next;   //从当前主设备的请示项队列中删除当前请求项
}


//对求项的初始化操作：
//	1. 若当前请求项为空，则返回
//	2. 若当前请求项的主设备号与当前块设备号不一致，则系统终止
//	3. 若当前请求项的缓冲区未上锁，则系统终止。
#define INIT_REQUEST \
repeat:\
	if(!CURRENT) \
		return;\
	if(MAJOR(CURRENT->dev)!=MAJOR_NR)\
		panic(DEVICE_NAME":request list destroyed");\
	if(CURRENT->bh){\
		if(!CURRENT->bh->b_lock)\
			panic(DEVICE_NAME":block not locked");\
	}


#endif

#endif
